#pragma once

#include "znx_defs.h"

typedef struct {
    size_t          len;
    u_char          *data;
} znx_str_t;

#define ZNX_STRING(str)                 { strlen(str), (u_char *)str }
#define ZNX_NULL_STRING                 { 0, NULL }
#define ZNX_STR_SET(dest, str)          (dest)->len = strlen(str); (dest)->data = (u_char *)(str)
#define ZNX_STR_SET_NULL(dest)          (dest)->len = 0; (dest)->data = NULL

#define znx_strncmp(s1, s2, n)          strncmp((const char *)s1, (const char *)s2, n)
#define znx_strcmp(s1, s2)              strcmp((const char *)s1, (const char *)s2)
#define znx_strncasecmp(s1, s2, n)      strncasecmp((const char *)s1, (const char *)s2, n)
#define znx_strcasecmp(s1, s2)          strcasecmp((const char *)s1, (const char *)s2)
#define znx_strstr(s1, s2)              strstr((const char *)s1, (const char *)s2)
#define znx_strlen(s)                   strlen((const char *)s)
#define znx_strchr(s1, c)               strchr((const char *)s1, (int) c)
#define znx_memzero(buf, n)             (void) memset(buf, 0, n)
#define znx_memset(buf, c, n)           (void) memset(buf, c, n)
#define znx_memcpy(dst, src, n)         (void) memcpy(dst, src, n)
#define znx_cpymem(dst, src, n)         (((u_char *) memcpy(dst, src, n)) + (n))
#define znx_memmove(dst, src, n)        (void) memmove(dst, src, n)
#define znx_memcmp(s1, s2, n)           memcmp(s1, s2, n)
#define znx_qsort                       qsort
#define znx_tolower(c)                  (u_char)((c >= 'A' && c <= 'Z') ? (c | 0x20) : c)
#define znx_toupper(c)                  (u_char)((c >= 'a' && c <= 'z') ? (c & ~0x20) : c)

void znx_strlow(u_char *dst, u_char *src, size_t n);
void znx_sort(void *base, size_t n, size_t size,
    int (*cmp)(const void *, const void *));
u_char *znx_hex_dump(u_char *dst, u_char *src, size_t len);

int znx_str_cmp(const znx_str_t *str1, const znx_str_t *str2);
int znx_str_cmp_ext(const znx_str_t *str1, const char *str2);
int znx_str_case_cmp(const znx_str_t *str1, const znx_str_t *str2);
int znx_str_case_cmp_ext(const znx_str_t *str1, const char *str2);


znx_bool_t znx_str_to_cstr(const znx_str_t *str, u_char *buf, size_t buf_size);
znx_bool_t znx_str_to_int64(znx_str_t *str, int64_t *res);
znx_bool_t znx_str_to_double(znx_str_t *str, double *res);

const char *znx_path_base(const char *path);
znx_bool_t znx_parse_size(const u_char *str, int64_t *res);

u_char *znx_cpystrn(u_char *dst, u_char *src, size_t n);
void znx_strrev(u_char *buf, size_t n);

u_char *znx_sprintf(u_char *buf, const char *fmt, ...);
u_char *znx_snprintf(u_char *buf, size_t max, const char *fmt, ...);
u_char *znx_slprintf(u_char *buf, u_char *last, const char *fmt,
    ...);
u_char *znx_vslprintf(u_char *buf, u_char *last, const char *fmt, va_list args);
#define znx_vsnprintf(buf, max, fmt, args)  \
    znx_vslprintf(buf, buf + (max), fmt, args)


static inline znx_bool_t
znx_strlen_try(const u_char *str, size_t max, size_t *len)
{
    for (size_t i = 0; i < max; i++) {
        if (*(str+i) == '\0') {
            *len = i;
            return ZNX_TRUE;
        }
    }

    return ZNX_FALSE;
}

static inline u_char *
znx_strlchr(u_char *p, u_char *last, u_char c)
{
    while (p < last) {

        if (*p == c) {
            return p;
        }

        p++;
    }

    return NULL;
}

typedef struct {
    znx_str_t                       key;
    znx_str_t                       value;
} znx_keyval_t;

